package com.enlorenz.support.bank.iso8583.msg;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import com.enlorenz.common.util.CodeUtils;
import com.enlorenz.common.util.ReflectionUtils;
import com.enlorenz.core.annotation.Property;
import com.enlorenz.core.enu.EnumUtils;
import com.enlorenz.support.bank.iso8583.Iso8583Utils;
import com.enlorenz.support.bank.iso8583.IsoCategory;
import com.enlorenz.support.bank.iso8583.IsoConfig;
import com.enlorenz.support.bank.iso8583.IsoProperty;
import com.enlorenz.support.bank.iso8583.IsoVisible;
import com.enlorenz.support.bank.iso8583.IsoWrapper;
import com.solab.iso8583.IsoMessage;
import com.solab.iso8583.IsoType;

/**
 * 消费请求报文
 * @author Karma
 */
public class Iso8583Fields {
	//ISO配置参数
	public static final IsoConfig ISO_CONFIG=
			new IsoConfig(Iso8583Fields.class);
	//可用域集合
	private Set<Integer> fieldSet;
	//类型
	private Integer type;
	
	/**
	 * 获取类型描述
	 * @return
	 */
	public String getTypeDesc() {
		if(null == type){
			return null;
		}
		return CodeUtils.integer2HexString(type);
	}
	

	public int getType() {
		return type;
	}

	public void setType(int type) {
		this.type = type;
	}

	/**
	 * 获取域集合
	 * @return 域集合
	 */
	public Set<Integer> getFieldSet() {
		if(null == fieldSet){
			List<IsoWrapper> isoList=ISO_CONFIG.getIsoWrapperList();
			fieldSet=new LinkedHashSet<Integer>(isoList.size());
			for(IsoWrapper iso:isoList){
				Object val=ReflectionUtils.getValueFromField(iso.getFieldName(),this);
				if(null!=val){
					fieldSet.add(iso.getIndex());
				}
			}
		}
		return fieldSet;
	}

	/**
	 * 是否包含域
	 * @param index 域序列
	 * @return 是否包含
	 */
	public boolean hasField(int index){
		return getFieldSet().contains(index);
	}
	
	/**
	 * 加载isoMessage数据
	 * @param isoMessage 数据
	 */
	public void load(IsoMessage isoMessage){
		fieldSet=Iso8583Utils.
				parseIsoMessage2Object(this,ISO_CONFIG, isoMessage);
	}
	
	/**
	 * 打印消息
	 */
	public void print(){
		Iso8583Utils.print(this, ISO_CONFIG);
	}
	
	/**
	 * 设置属性
	 * @param index 序列
	 * @param value 值
	 */
	public void setValue(int index,Object value){
		IsoWrapper isoWrapper=
				ISO_CONFIG.getIsoWrapperByIndex(index);
		if(null == isoWrapper){
			return;
		}
		ReflectionUtils.setValue2Field(
				isoWrapper.getFieldName(), this, value);
		if(null == fieldSet){
			fieldSet=new LinkedHashSet<Integer>();
		}
		fieldSet.add(index);
	}
	
	/**
	 * 获取值
	 * @param index 序列
	 * @return
	 */
	public Object getValue(int index){
		IsoWrapper isoWrapper=
				ISO_CONFIG.getIsoWrapperByIndex(index);
		if(null == isoWrapper){
			return null;
		}
		return Iso8583Utils.getIsoData(this, isoWrapper.getFieldName(), isoWrapper.getIsoProperty());
	}
	
	//n..19(LLVAR)
	//Primary Account Number
	@IsoProperty(index=2,isoType=IsoType.LLVAR,length=19
			,category=IsoCategory.NUMBER)
	@Property(name="主账号")
	private String pan;
	
	//n6，6位定长数字。
	@IsoProperty(index=3,isoType=IsoType.ALPHA,length=6
			,category=IsoCategory.NUMBER)
	@Property(name="处理码")
	private String processingCode;
	
	private ProcessingCodeEnum processingCodeEnum; 
	
	public String getProcessingCode() {
		return processingCode;
	}
	public void setProcessingCode(String processingCode) {
		this.processingCode = processingCode;
		processingCodeEnum=(ProcessingCodeEnum)
				EnumUtils.locateEnumStatus(processingCode, ProcessingCodeEnum.class);
	}
	
	public ProcessingCodeEnum getProcessingCodeEnum() {
		return processingCodeEnum;
	}

	//n12
	@IsoProperty(index=4,isoType=IsoType.ALPHA,length=12
			,category=IsoCategory.NUMBER)
	@Property(name="交易金额")
	private String amount;
	
	//n10
	@IsoProperty(index=7,isoType=IsoType.ALPHA,length=10
			,category=IsoCategory.NUMBER)
	@Property(name="传输日期和时间")
	private String transDatetime;
	
	//n6
	@IsoProperty(index=11,isoType=IsoType.ALPHA,length=6
			,category=IsoCategory.NUMBER)
	@Property(name="系统跟踪号")
	private String sysTraceAuditNo;
	
	//n6 hhmmss
	@IsoProperty(index=12,isoType=IsoType.ALPHA,length=6
			,category=IsoCategory.NUMBER)
	@Property(name="本地交易时间")
	private String localTime;
	
	//n4 MMDD
	@IsoProperty(index=13,isoType=IsoType.ALPHA,length=4
			,category=IsoCategory.NUMBER)
	@Property(name="本地交易日期")
	private String localDate;
	
	//n4 YYMM
	@IsoProperty(index=14,isoType=IsoType.ALPHA,length=4
			,category=IsoCategory.NUMBER)
	@Property(name="卡片有效日期")
	private String cardExpiration;
	
	//n4 MMDD
	@IsoProperty(index=15,isoType=IsoType.ALPHA,
			length=4,visible=IsoVisible.RES
			,category=IsoCategory.NUMBER)
	@Property(name="清算日期")
	private String settleDate;
	
	//n4
	@IsoProperty(index=18,isoType=IsoType.ALPHA,length=4
			,visible=IsoVisible.REQ,category=IsoCategory.NUMBER)
	@Property(name="商户类型")
	private String merchantType;
	
	//n3
	@IsoProperty(index=22,isoType=IsoType.ALPHA,length=3
			,visible=IsoVisible.REQ,category=IsoCategory.NUMBER)
	@Property(name="服务点输入方式码",desc="服务点输入方式码,即持卡人数据（如PAN 和PIN）的输入方式。服务点（point of service） 是指各种交易始发场合")
	private String serviceEntryModeCode;
	
	//n3
	@IsoProperty(index=23,isoType=IsoType.ALPHA,length=3
			,category=IsoCategory.NUMBER)
	@Property(name="卡片序列号")
	private String cardSeqNo;
	
	//n2 82-消费
	@IsoProperty(index=25,isoType=IsoType.ALPHA,length=2
			,category=IsoCategory.NUMBER)
	@Property(name="服务点条件码")
	private String serviceConditionMode;
	
	//n2
	@IsoProperty(index=26,isoType=IsoType.ALPHA,length=2
			,visible=IsoVisible.REQ,category=IsoCategory.NUMBER)
	@Property(name="服务点PIN采集代码")
	private String servicePinCaptureCode;
	
	//n..11(LLVAR)
	//Acquiring Institution Identification Code
	@IsoProperty(index=32,isoType=IsoType.LLVAR,length=11
			,category=IsoCategory.NUMBER)
	@Property(name="受理机构标识码")
	private String acqInsIdenCode;
	
	//n..11(LLVAR)
	//Forwarding Institution Identification Code
	@IsoProperty(index=33,isoType=IsoType.LLVAR,length=11
			,category=IsoCategory.NUMBER)
	@Property(name="发送机构标识码")
	private String forwInsIdenCode;
	
	//z..37
	@IsoProperty(index=35,isoType=IsoType.LLBIN,length=40
			,visible=IsoVisible.REQ,category=IsoCategory.NONE)
	@Property(name="第二磁道数据")
	private byte [] t2;
	//z...104
	@IsoProperty(index=36,isoType=IsoType.LLLBIN,length=104
			,visible=IsoVisible.REQ,category=IsoCategory.NONE)
	@Property(name="第三磁道数据")
	private byte [] t3;
	
	//an12
	@IsoProperty(index=37,isoType=IsoType.ALPHA,length=12
			,category=IsoCategory.ALPHA_NUMBER)
	@Property(name="检索参考号")
	private String queryCode;
	
	//an6
	@IsoProperty(index=38,isoType=IsoType.ALPHA,length=6
			,visible=IsoVisible.RES,category=IsoCategory.ALPHA_NUMBER)
	@Property(name="授权标识应答码")
	private String authResCode;
	
	//an2
	@IsoProperty(index=39,isoType=IsoType.ALPHA,length=2
			,visible=IsoVisible.RES,category=IsoCategory.ALPHA_NUMBER)
	@Property(name="响应码")
	private String resCode;
	

	//ans8
	@IsoProperty(index=41,isoType=IsoType.ALPHA,length=8
			,category=IsoCategory.ALPHA_NUMBER_SPACIAL)
	@Property(name="受卡机终端标识码")
	private String recvTermSignCode;
	
	//ans15
	@IsoProperty(index=42,isoType=IsoType.ALPHA,length=15
			,category=IsoCategory.ALPHA_NUMBER_SPACIAL)
	@Property(name="受卡方标识码")
	private String recvSignCode;
	
	//ans40
	@IsoProperty(index=43,isoType=IsoType.ALPHA,length=40
			,visible=IsoVisible.REQ,category=IsoCategory.ALPHA_NUMBER_SPACIAL)
	@Property(name="受卡方名称地址")
	private String recvNameAddr;
	
	//ans…600
	@IsoProperty(index=48,isoType=IsoType.LLLVAR,length=600
			,category=IsoCategory.ALPHA_NUMBER_SPACIAL)
	@Property(name="自定义域")
	private String custom;
	
	//an3
	@IsoProperty(index=49,isoType=IsoType.ALPHA,length=3
			,category=IsoCategory.ALPHA_NUMBER)
	@Property(name="交易货币代码")
	private String currencyCode;
	
	
	//n16
	@IsoProperty(index=53,isoType=IsoType.ALPHA,length=16
			,visible=IsoVisible.REQ
			,category=IsoCategory.NUMBER)
	@Property(name="安全控制信息")
	private String safeInfo;
	
	//an...040(LLLVAR)
	@IsoProperty(index=54,isoType=IsoType.LLLVAR,length=40
			,visible=IsoVisible.REQ
			,category=IsoCategory.ALPHA_NUMBER)
	@Property(name="实际余额")
	private String additionalAmounts;
	
	
	@IsoProperty(index=55,isoType=IsoType.LLLBIN,length=145
			,category=IsoCategory.NONE)
	@Property(name="IC卡数据域")
	private byte [] icData;
	
	//ans…600
	@IsoProperty(index=59,isoType=IsoType.LLLVAR,length=600
			,category=IsoCategory.ALPHA_NUMBER_SPACIAL)
	@Property(name="查询明细")
	private String queryDetails;
	
	//ans..100(LLLVAR)
	@IsoProperty(index=60,isoType=IsoType.LLLVAR,length=100
			,category=IsoCategory.ALPHA_NUMBER_SPACIAL)
	@Property(name="自定义域2")
	private String custom2;
	
	//ans...255(LLLVAR)
	@IsoProperty(index=61,isoType=IsoType.LLLVAR,length=255
			,visible=IsoVisible.REQ,category=IsoCategory.ALPHA_NUMBER_SPACIAL)
	@Property(name="持卡人身份认证信息")
	private String identiyInfo;
	//ANS...512(LLLVAR)
	@IsoProperty(index=63,isoType=IsoType.LLLVAR,length=512
			,category=IsoCategory.ALPHA_NUMBER_SPACIAL)
	@Property(name="自定义域4")
	private String custom4;
	
	//n3
	@IsoProperty(index=70,isoType=IsoType.ALPHA,length=3
			,category=IsoCategory.NUMBER)
	@Property(name="网络管理码")
	private String networkCode;
	
	//n42
	@IsoProperty(index=90,isoType=IsoType.ALPHA,length=42
			,category=IsoCategory.NUMBER)
	@Property(name="原始数据元")
	private String orginData;
	
	//64bit
	@IsoProperty(index=96,isoType=IsoType.BINARY,length=8
			,category=IsoCategory.NONE)
	@Property(name="报文安全码")
	private byte [] msgSecCode;
	
	@IsoProperty(index=100,isoType=IsoType.LLVAR,length=11
			,visible=IsoVisible.RES
			,category=IsoCategory.NONE)
	@Property(name="接收机构标识码")
	private String recvOrgnCode;
	
	
	@IsoProperty(index=102,isoType=IsoType.LLVAR,length=28
			,visible=IsoVisible.RES
			,category=IsoCategory.NONE)
	@Property(name="账户标识 1")
	private String accountIden1;
	@IsoProperty(index=103,isoType=IsoType.LLVAR,length=28
			,visible=IsoVisible.RES,category=IsoCategory.NONE)
	@Property(name="账户标识 2")
	private String accountIden2;
	
	//64bit
	@IsoProperty(index=52,isoType=IsoType.BINARY,length=8
			,visible=IsoVisible.REQ,category=IsoCategory.NONE)
	@Property(name="个人密码")
	private byte [] pwd;
		
	//64bit
	@IsoProperty(index=128,isoType=IsoType.BINARY,length=8
			,category=IsoCategory.NONE)
	@Property(name="自定义域3")
	private byte [] mac;
	
	public String getPan() {
		return pan;
	}
	public void setPan(String pan) {
		this.pan = pan;
	}
	
	public String getAmount() {
		return amount;
	}
	public void setAmount(String amount) {
		this.amount = amount;
	}
	public String getTransDatetime() {
		return transDatetime;
	}
	public void setTransDatetime(String transDatetime) {
		this.transDatetime = transDatetime;
	}
	public String getSysTraceAuditNo() {
		return sysTraceAuditNo;
	}
	public void setSysTraceAuditNo(String sysTraceAuditNo) {
		this.sysTraceAuditNo = sysTraceAuditNo;
	}
	public String getLocalTime() {
		return localTime;
	}
	public void setLocalTime(String localTime) {
		this.localTime = localTime;
	}
	public String getLocalDate() {
		return localDate;
	}
	public void setLocalDate(String localDate) {
		this.localDate = localDate;
	}
	public String getCardExpiration() {
		return cardExpiration;
	}
	public void setCardExpiration(String cardExpiration) {
		this.cardExpiration = cardExpiration;
	}
	public String getSettleDate() {
		return settleDate;
	}
	public void setSettleDate(String settleDate) {
		this.settleDate = settleDate;
	}
	public String getMerchantType() {
		return merchantType;
	}
	public void setMerchantType(String merchantType) {
		this.merchantType = merchantType;
	}
	public String getServiceEntryModeCode() {
		return serviceEntryModeCode;
	}
	public void setServiceEntryModeCode(String serviceEntryModeCode) {
		this.serviceEntryModeCode = serviceEntryModeCode;
	}
	public String getCardSeqNo() {
		return cardSeqNo;
	}
	public void setCardSeqNo(String cardSeqNo) {
		this.cardSeqNo = cardSeqNo;
	}
	public String getServiceConditionMode() {
		return serviceConditionMode;
	}
	public void setServiceConditionMode(String serviceConditionMode) {
		this.serviceConditionMode = serviceConditionMode;
	}
	public String getServicePinCaptureCode() {
		return servicePinCaptureCode;
	}
	public void setServicePinCaptureCode(String servicePinCaptureCode) {
		this.servicePinCaptureCode = servicePinCaptureCode;
	}
	public String getAcqInsIdenCode() {
		return acqInsIdenCode;
	}
	public void setAcqInsIdenCode(String acqInsIdenCode) {
		this.acqInsIdenCode = acqInsIdenCode;
	}
	public String getForwInsIdenCode() {
		return forwInsIdenCode;
	}
	public void setForwInsIdenCode(String forwInsIdenCode) {
		this.forwInsIdenCode = forwInsIdenCode;
	}
	public byte [] getT2() {
		return t2;
	}
	public void setT2(byte [] t2) {
		this.t2 = t2;
	}
	public byte [] getT3() {
		return t3;
	}
	public void setT3(byte [] t3) {
		this.t3 = t3;
	}
	public String getQueryCode() {
		return queryCode;
	}
	public void setQueryCode(String queryCode) {
		this.queryCode = queryCode;
	}
	public String getAuthResCode() {
		return authResCode;
	}
	public void setAuthResCode(String authResCode) {
		this.authResCode = authResCode;
	}
	public String getResCode() {
		return resCode;
	}
	public void setResCode(String resCode) {
		this.resCode = resCode;
	}
	public String getRecvTermSignCode() {
		return recvTermSignCode;
	}
	public void setRecvTermSignCode(String recvTermSignCode) {
		this.recvTermSignCode = recvTermSignCode;
	}
	public String getRecvSignCode() {
		return recvSignCode;
	}
	public void setRecvSignCode(String recvSignCode) {
		this.recvSignCode = recvSignCode;
	}
	public String getRecvNameAddr() {
		return recvNameAddr;
	}
	public void setRecvNameAddr(String recvNameAddr) {
		this.recvNameAddr = recvNameAddr;
	}
	public String getCustom() {
		return custom;
	}
	public void setCustom(String custom) {
		this.custom = custom;
	}
	public String getCurrencyCode() {
		return currencyCode;
	}
	public void setCurrencyCode(String currencyCode) {
		this.currencyCode = currencyCode;
	}
	public byte [] getPwd() {
		return pwd;
	}
	public void setPwd(byte [] pwd) {
		this.pwd = pwd;
	}
	public String getSafeInfo() {
		return safeInfo;
	}
	public void setSafeInfo(String safeInfo) {
		this.safeInfo = safeInfo;
	}
	public String getAdditionalAmounts() {
		return additionalAmounts;
	}
	public void setAdditionalAmounts(String additionalAmounts) {
		this.additionalAmounts = additionalAmounts;
	}
	public byte [] getIcData() {
		return icData;
	}
	public void setIcData(byte [] icData) {
		this.icData = icData;
	}
	public String getQueryDetails() {
		return queryDetails;
	}
	public void setQueryDetails(String queryDetails) {
		this.queryDetails = queryDetails;
	}
	public String getCustom2() {
		return custom2;
	}
	public void setCustom2(String custom2) {
		this.custom2 = custom2;
	}
	public String getIdentiyInfo() {
		return identiyInfo;
	}
	public void setIdentiyInfo(String identiyInfo) {
		this.identiyInfo = identiyInfo;
	}
	public String getCustom4() {
		return custom4;
	}
	public void setCustom4(String custom4) {
		this.custom4 = custom4;
	}
	public String getNetworkCode() {
		return networkCode;
	}
	public void setNetworkCode(String networkCode) {
		this.networkCode = networkCode;
	}
	public String getOrginData() {
		return orginData;
	}
	public void setOrginData(String orginData) {
		this.orginData = orginData;
	}
	public byte [] getMsgSecCode() {
		return msgSecCode;
	}
	public void setMsgSecCode(byte [] msgSecCode) {
		this.msgSecCode = msgSecCode;
	}
	public String getRecvOrgnCode() {
		return recvOrgnCode;
	}
	public void setRecvOrgnCode(String recvOrgnCode) {
		this.recvOrgnCode = recvOrgnCode;
	}
	public String getAccountIden1() {
		return accountIden1;
	}
	public void setAccountIden1(String accountIden1) {
		this.accountIden1 = accountIden1;
	}
	public String getAccountIden2() {
		return accountIden2;
	}
	public void setAccountIden2(String accountIden2) {
		this.accountIden2 = accountIden2;
	}
	public byte [] getMac() {
		return mac;
	}
	public void setMac(byte [] mac) {
		this.mac = mac;
	}
	
	public static void main(String[] args) {
		
		
		Iso8583Fields crm=new Iso8583Fields();
		crm.setPan("pan");
		crm.setProcessingCode("280000");
		crm.setAmount("000000000003");
		crm.setTransDatetime("0731131206");
		crm.setSysTraceAuditNo("005871");
		crm.setLocalTime("131206");
		crm.setLocalDate("0731");
		crm.setServiceEntryModeCode("021");
		crm.setServiceConditionMode("82");
		crm.setServicePinCaptureCode("06");
		crm.setAcqInsIdenCode("0004000012");
		crm.setForwInsIdenCode("0004000012");
		crm.setT2(CodeUtils.hexString2Bytes("309765BB2AB92E9952EE9F79D4C2F9B1096F088D942442732FCEB5C9B5F74C919D00"));
		crm.setT3(CodeUtils.hexString2Bytes("309765BB2AB92E9952EE9F79D4C2F9B1096F088D942442732FCEB5C9B5F74C919D00"));
		
		crm.setQueryCode("000000000002");
		crm.setRecvTermSignCode("000068");
		crm.setRecvSignCode("000000000000000");
		crm.setRecvNameAddr("ceshishanghu");
		crm.setCustom("000068");
		crm.setCurrencyCode("156");
		crm.setOrginData("020000587107311312060000400001200004000012");
		crm.setPwd(CodeUtils.hexString2Bytes("2679637F5AB5EE47"));
		byte [] buff=Iso8583Utils.create(0x200,crm,4);
		
		String xml=Iso8583Utils.createParseXml(0x200, Iso8583Fields.class); 
		IsoMessage im=Iso8583Utils.parse(xml,buff,4);
		System.out.println(im);
		
		/*Iso8583Fields crm=new Iso8583Fields();
		crm.setForwInsIdenCode("heyman");
		crm.setT3(CodeUtils.hexString2Bytes("3097"));
		crm.setCustom("000068");
		byte [] buff=Iso8583Utils.create(0x200,crm,4);
		System.out.println("["+new String(buff)+"]");
		String xml=Iso8583Utils.createParseXml(0x200, 
				Iso8583Fields.class); 
		IsoMessage im=Iso8583Utils.parse(xml,buff,4);
		System.out.println(im);*/
		
		/*Iso8583Fields crm=new Iso8583Fields();
		crm.setForwInsIdenCode("0004000012");
		crm.setT2(CodeUtils.hexString2Bytes("169CB9627F6006607AF9B562C89F46646A4C887257578E2711B798DDA2B6E462736355906CD8B09A"));
		crm.setQueryCode("000000000002");
		crm.setRecvNameAddr("test");
		
		byte [] buff=Iso8583Utils.create(0x200,crm,4);
		System.out.println(new String(buff));
		String xml=Iso8583Utils.createParseXml(0x200, Iso8583Fields.class); 
		IsoMessage im=Iso8583Utils.parse(xml,buff,4);
		System.out.println(new String(buff));*/
	}
}
